package web.stu.controller;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import web.stu.common.ErrorCode;
import web.stu.config.Result;
import web.stu.exception.BusinessException;
import web.stu.mapper.CourseMapper;
import web.stu.model.dto.CourseDTO;
import web.stu.model.dto.course.QueryCourseDTO;
import web.stu.model.entity.Course;
import web.stu.model.entity.User;
import web.stu.model.enums.UserRoleEnum;
import web.stu.model.vo.CourseVO;
import web.stu.service.CourseService;
import web.stu.service.UserService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 课程管理控制器
 * <p>
 * 提供课程相关的REST API，包括：
 * - 课程的增删改查
 * - 分页查询课程
 * - 按条件筛选课程
 * - 学生选课相关操作
 * </p>
 */
@Slf4j
@RestController
@RequestMapping("/course")
@Api(value = "课程的管理模块", tags = "课程模块")
public class CourseController {

    @Resource
    private CourseService courseService;

    @Resource
    private UserService userService;

    @Resource
    private CourseMapper courseMapper;

    /**
     * 分页查询课程信息接口
     * @param queryCourseDTO 查询条件，包含学生ID、课程ID、页码、每页大小等筛选条件
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含分页课程信息的Result对象，包括总记录数、当前页数据等
     * @throws BusinessException 如果查询参数无效或用户未登录会抛出异常
     * @apiNote 支持按学生ID或课程ID进行条件筛选，返回的课程信息包含详细属性。
     *          分页参数默认值：页码=1，每页大小=10。
     *          返回的课程信息包括：课程ID、课程名称、学分、授课教师等。
     */
    @PostMapping("/page")
    @ApiOperation(value = "pageCourses", notes = "分页查询根据学生id/课程id查询课程信息")
    public Result<Page<CourseVO>> pageCourses(@RequestBody QueryCourseDTO queryCourseDTO, HttpServletRequest request) {
        Page<CourseVO> coursePage = courseService.pageCourses(queryCourseDTO, request);
        return Result.success(coursePage);
    }

    /**
     * 获取课程列表接口
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含课程列表的Result对象
     * @throws BusinessException 如果用户未登录会抛出异常
     * @apiNote 对于学生用户，会返回带有授课教师信息的课程列表。
     *          注意：当学生未选择任何课程时，将返回所有可选课程列表。
     *          对于其他角色用户，返回基本课程信息列表。
     */
    @GetMapping("/list")
    @ApiOperation(value = "listAllCourses", notes = "获取所有课程列表，学生用户会返回带有教师信息的课程列表")
    public Result<List<CourseVO>> listAllCourse(HttpServletRequest request) {
        List<Course> courseList = courseService.list();
        //如果为学生需要处理
        User loginUser = userService.getLoginUser(request);
        boolean isStudent = userService.isCompareRole(loginUser, UserRoleEnum.STUDENT.getKey());
        List<CourseVO> courseVOList = courseList.stream().map(course -> {
            CourseVO courseVO = BeanUtil.copyProperties(course, CourseVO.class);
            //如果为学生需要处理
            if (isStudent) {
                String teacherName = courseMapper.getTeacherByStudentCourse(loginUser.getId(), course.getId());
                courseVO.setTeacherName(teacherName);
            }
            return courseVO;
        }).collect(Collectors.toList());

        return Result.success(courseVOList);
    }

//    @Deprecated
//    @PostMapping("/page/deprecated")
//    public Result<Page<Course>> pageCourses(
//            @RequestParam(defaultValue = "1") Integer pageNum,
//            @RequestParam(defaultValue = "10") Integer pageSize) {
//        Page<Course> page = courseService.pageCourses(pageNum, pageSize);
//        return Result.success(page);
//    }

    /**
     * 添加新课程接口
     * @param courseDTO 课程信息数据传输对象，包含课程名称、学分等信息
     * @return 空的Result对象，表示操作成功
     * @throws BusinessException 如果课程信息无效会抛出异常
     * @apiNote 添加新课程时，课程名称不能重复，学分必须大于0
     */
    @PostMapping("/add")
    @ApiOperation(value = "添加新课程", notes = "添加一个新的课程，需要管理员权限")
    public Result<Void> addCourse(@RequestBody CourseDTO courseDTO) {

        courseService.addCourse(courseDTO);
        return Result.success();
    }

    /**
     * 更新课程信息接口
     * @param courseDTO 课程信息数据传输对象，包含需要更新的课程信息
     * @param request HTTP请求对象，用于获取会话信息
     * @return 空的Result对象，表示操作成功
     * @throws BusinessException 如果课程信息无效或用户无权限会抛出异常
     * @apiNote 更新课程时会验证用户权限，课程名称不能与其他课程重复
     */
    @PutMapping("/update")
    @ApiOperation(value = "更新课程信息", notes = "更新现有课程的信息，需要管理员权限")
    public Result<Void> updateCourse(@RequestBody CourseDTO courseDTO, HttpServletRequest request) {

        courseService.updateCourse(courseDTO, request);
        return Result.success();

    }

    /**
     * 删除课程接口
     * @param id 要删除的课程ID
     * @param request HTTP请求对象，用于获取会话信息
     * @return 空的Result对象，表示操作成功
     * @throws BusinessException 如果课程不存在、已有学生选课或用户无权限会抛出异常
     * @apiNote 删除课程前会检查是否有学生已选该课程，如果有则不允许删除。
     *          只有管理员有权限删除课程。
     */
    @DeleteMapping("/delete/{id}")
    @ApiOperation(value = "删除课程", notes = "根据课程ID删除课程，需要管理员权限")
    public Result<Void> deleteCourse(@PathVariable Integer id, HttpServletRequest request) {

        courseService.deleteCourseById(id, request);
        return Result.success();
    }

    /**
     * 根据ID获取课程详情接口
     * @param id 课程ID
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含课程详细信息的Result对象
     * @throws BusinessException 如果课程不存在会抛出异常
     * @apiNote 返回的课程信息包含基本属性和关联的教师信息（如果有）
     */
    @GetMapping("/get/{id}")
    @ApiOperation(value = "获取课程详情", notes = "根据课程ID获取课程详细信息")
    public Result<CourseVO> getCourseById(@PathVariable Integer id, HttpServletRequest request) {
        CourseVO course = courseService.getCourseById(id, request);
        return Result.success(course);
    }

    /**
     * 查询特定组合条件下的课程列表
     * @param studentId 学生ID
     * @param teacherId 教师ID
     * @param classId 班级ID
     * @param request HTTP请求对象，用于获取会话信息
     * @return 包含符合条件的课程列表的Result对象
     * @throws BusinessException 如果任何ID参数为空，或用户未登录会抛出异常
     * @apiNote 此接口用于查询同时满足以下条件的课程：
     *          1. 指定学生已选择的课程
     *          2. 指定教师教授的课程
     *          3. 指定班级开设的课程
     *          返回的课程信息包含课程基本信息和教师信息
     */
    @GetMapping("/list/studentAndTeacherAndClass")
    @ApiOperation(value = "多条件查询课程", notes = "根据学生ID、教师ID和班级ID查询课程列表")
    public Result<List<CourseVO>> listCourseByStudentIdAndTeacherIdAndClassId(@RequestParam("studentId") Integer studentId, @RequestParam("teacherId") Integer teacherId, @RequestParam("classId") Integer classId, HttpServletRequest request) {
        // 非空判断
        if (studentId == null || teacherId == null || classId == null) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        List<CourseVO> courseVOList = courseService.listCourseByStudentIdAndTeacherIdAndClassId(studentId, teacherId, classId, request);
        return Result.success(courseVOList);
    }

}